package com.atguigu.gmall.payment.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.model.enums.PaymentType;
import com.atguigu.gmall.model.payment.PaymentInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api/payment/alipay")
@Slf4j
public class AlipayController {

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${app_id}")
    private String app_id;


    //  生成二维码的返回值！
    //  http://api.gmall.com/api/payment/alipay/submit/44

    /**
     * 生成支付二维码
     * @param orderId
     * @return
     */
    @GetMapping("/submit/{orderId}")
    public String  submitPay(@PathVariable Long orderId){
        //  调用生成二维码方法
        String form = null;
        try {
            form = alipayService.createAliPay(orderId);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        //  返回
        return form;
    }

    //  获取?后面的参数
    //  http://api.gmall.com/api/payment/alipay/callback/return?charset=utf-8&out_trade_no=ATGUIGU1681888683206759&method=alipay.trade.page.pay.return&total_amount=0.01&sign=avhGwCgS7OuxZIIV9kJpKyEBhBCdFp%2BOSrmQORJ3QqtVQ8NDJFAbOlI%2FSKqtotes3Wh7JfUlor2uNBOAvIUN6eBSMZFPSEmAJAoFW5VHJsaoS0oFthsJd86sJpxYh56aKd102nqPQpBGQM%2FRy9rNi2ROI1dx0yvp19vP0nVf8CydEuzrNirL2xITmWL%2FOpUHm08L1kC2K7ST8tzvNdfG6e4mG6p8WEBNXwmJyk5yhMeAc0ORCOhxlo2644yearKadaRd0HxeSAmOzZRdayXIwvDaK%2F0Hid0fvK1Y9oz4kN%2B2hMLUbpbm1Qa2yEccJ6xNz5N1ruXrq6qnGPMEl%2BoA7w%3D%3D&trade_no=2023041922001461931400924704&auth_app_id=2021001163617452&version=1.0&app_id=2021001163617452&sign_type=RSA2&seller_id=2088831489324244&timestamp=2023-04-19+15%3A21%3A02
    @GetMapping("/callback/return")
    public void callbackReturn(@RequestParam HashMap<String,String> map, HttpServletResponse response) throws IOException {
        //  可以做更新交易记录或订单状态.
        System.out.println(map);
        //  http://payment.gmall.com/pay/success.html
        response.sendRedirect(AlipayConfig.return_order_url);
    }

    /**
     * 异步通知
     * @param paramsMap 获取异步通知参数
     * https: //商家网站通知地址?voucher_detail_list=[{"amount":"0.20","merchantContribute":"0.00","name":"5折券","otherContribute":"0.20","type":"ALIPAY_DISCOUNT_VOUCHER","voucherId":"2016101200073002586200003BQ4"}]&fund_bill_list=[{"amount":"0.80","fundChannel":"ALIPAYACCOUNT"},{"amount":"0.20","fundChannel":"MDISCOUNT"}]&subject=PC网站支付交易&trade_no=2016101221001004580200203978&gmt_create=2016-10-12 21:36:12&notify_type=trade_status_sync&total_amount=1.00&out_trade_no=mobile_rdm862016-10-12213600&invoice_amount=0.80&seller_id=2088201909970555&notify_time=2016-10-12 21:41:23&trade_status=TRADE_SUCCESS&gmt_payment=2016-10-12 21:37:19&receipt_amount=0.80&passback_params=passback_params123&buyer_id=2088102114562585&app_id=2016092101248425&notify_id=7676a2e1e4e737cff30015c4b7b55e3kh6& sign_type=RSA2&buyer_pay_amount=0.80&sign=***&point_amount=0.00
     * @return
     */
    @PostMapping("/callback/notify")
    public String callbackNotify(@RequestParam HashMap<String,String> paramsMap){
        System.out.println("死鬼，你才回来...");
        //  Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
        //  调用SDK验证签名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        //  判断
        if(signVerified){
            //  TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            //  1.2.4 系统校验
            //  1 获取支付宝传递过来的out_trade_no
            String outTradeNo = paramsMap.get("out_trade_no");
            //  2 获取订单总金额
            String totalAmount = paramsMap.get("total_amount");
            //  4 验证 app_id 是否为该商家本身
            String appId = paramsMap.get("app_id");
            //  并且过滤重复的通知结果数据 支付宝针对同一条异步通知重试时，异步通知参数中的 notify_id 是不变的。
            String notifyId = paramsMap.get("notify_id");
            //  outTradeNo 判断它是否与商家系统的订单号一致！
            //  获取交易状态 trade_status
            String tradeStatus = paramsMap.get("trade_status");

            try {
                PaymentInfo paymentInfo = paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
                //  判断 测试给的金额0.01 传递过来的肯定是0.01  != 26755
                if (paymentInfo == null || new BigDecimal("0.01").compareTo(new BigDecimal(totalAmount))!=0
                        ||  !appId.equals(app_id)){
                    return "failure";
                }
                //  保证消息的幂等性! setnx key value; 24*60 = 1440 + 22m
                Boolean result = this.redisTemplate.opsForValue().setIfAbsent(notifyId, notifyId, 1462, TimeUnit.MINUTES);
                if (!result){
                    //  停止后续业务处理！
                    return "failure";
                }
                //  判断交易状态
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){
                    //  修改交易状态：payment_status ; callback_time; callback_content; trade_no;
                    paymentService.updatePaymentInfoStatus(outTradeNo,PaymentType.ALIPAY.name(),paramsMap);
                    return "success";
                }
            } catch (Exception e) {
                //  删除缓存的key
                this.redisTemplate.delete(notifyId);
                log.error("处理异步通知失败 {}"+outTradeNo);
                throw new RuntimeException(e);
            }
        }else{
            // TODO 验签失败则记录异常日志，并在response中返回failure.
            return "failure";
        }
        return "failure";
    }

    /**
     * 退款控制器
     * @param orderId
     * @return
     */
    @GetMapping("refund/{orderId}")
    public Result refund(@PathVariable Long orderId){
        //  调用服务层方法
        Boolean flag = this.alipayService.refund(orderId);
        //  退款接口
        return Result.ok(flag);

    }

    /**
     * 关闭支付宝交易记录
     * @param orderId
     * @return
     */
    @GetMapping("closePay/{orderId}")
    public Boolean closePay(@PathVariable Long orderId){
        //  调用服务层关闭方法.
        Boolean flag = this.alipayService.closePay(orderId);
        //  返回结果
        return flag;
    }

    /**
     * 根据订单查看支付宝是否有交易记录
     * @param orderId
     * @return
     */
    @GetMapping("checkPayment/{orderId}")
    public Boolean checkPayment(@PathVariable Long orderId){
        //  调用服务层关闭方法.
        Boolean flag = this.alipayService.checkPayment(orderId);
        //  返回结果
        return flag;
    }

    /**
     * 查看是否有本地交易记录 为什么这里可以直接当参数直接传递进去！
     * @param outTradeNo
     * @return
     */
    @GetMapping("/getPaymentInfo/{outTradeNo}")
    public PaymentInfo getPaymentInfo(@PathVariable String outTradeNo){
        return this.paymentService.getPaymentInfo(outTradeNo,PaymentType.ALIPAY.name());
    }
}
